﻿using UnityEngine;

// 实现普通的单例模式
// where 限制模板的类型, new()指的是这个类型必须要能被实例化
public abstract class Singleton<T> where T : new() {
    private static T _instance;
    private static object mutex = new object();//多线程的锁，防止多线程访问时出现问题
    public static T Instance {
        get {
            if (_instance == null) {
                //保证多线程安全
                lock (mutex) {
                    if (_instance == null) {
                        _instance = new T();
                    }
                }
            }
            return _instance;
        }
    }
}


// Monobeavior: 声音, 网络
// Unity单例，保证全局唯一（节点+组件实例）不用保证线程安全，因为所有线程都在unity线程里面，unity线程只有一个

public class UnitySingleton<T> : MonoBehaviour
where T : Component {
    private static T _instance = null;
    public static T Instance {
        get {
            if (_instance == null) {
                _instance = FindObjectOfType(typeof(T)) as T;
                if (_instance == null) {
                    GameObject obj = new GameObject();
                    _instance = (T)obj.AddComponent(typeof(T));
                    obj.hideFlags = HideFlags.DontSave;//将该物体保留到新场景
                    // obj.hideFlags = HideFlags.HideAndDontSave;
                    obj.name = typeof(T).Name;
                }
            }
            return _instance;
        }
    }

    public virtual void Awake() {
        DontDestroyOnLoad(this.gameObject);
        if (_instance == null) {
            _instance = this as T;
        }
        else {
            GameObject.Destroy(this.gameObject);
        }
    }
}

public class UnitySingle<T> :MonoBehaviour
    where T:Component
{
    private static T instance;
    public static T Instance
    {
        get
        {
            if(instance == null)
            {
                instance = FindObjectOfType(typeof(T)) as T;
                if(instance == null)
                {
                    GameObject obj = new GameObject();
                    instance = (T)obj.gameObject.AddComponent(typeof(T));
                    obj.hideFlags = HideFlags.DontSave;
                    obj.name = typeof(T).Name;
                }
            }
            return instance;
        }
    }

    public virtual void Awake()
    {
        DontDestroyOnLoad(gameObject);
        if(instance == null)
        {
            instance = this as T;
        }
        else
        {
            Destroy(gameObject);
        }
    }
}

public class Single<T> where T : new()
{
    private static T instance;
    private static Object mute = new Object();
    public static T Instance
    {
        get
        {
            if(instance == null)
            {
                lock (mute)
                {
                    if(instance == null)
                        instance = new T();
                }
            }
            return instance;
        }
    }
}